home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / x / gui / xgif.lha / xgif / xgifload.c < prev   
Encoding:
C/C++ Source or Header  |  1990-02-07  |  14.0 KB  |  481 lines

  1. /*
  2.  * xgifload.c  -  based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  */
  24.  
  25. #include "xgif.h"
  26.  
  27. typedef int boolean;
  28.  
  29. #define NEXTBYTE (*ptr++)
  30. #define IMAGESEP 0x2c
  31. #define INTERLACEMASK 0x40
  32. #define COLORMAPMASK 0x80
  33.  
  34. FILE *fp;
  35.  
  36. int BitOffset = 0,        /* Bit Offset of next code */
  37.     XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  38.     Pass = 0,            /* Used by output routine if interlaced pic */
  39.     OutCount = 0,        /* Decompressor output 'stack count' */
  40.     RWidth, RHeight,        /* screen dimensions */
  41.     Width, Height,        /* image dimensions */
  42.     LeftOfs, TopOfs,        /* image offset */
  43.     BitsPerPixel,        /* Bits per pixel, read from GIF header */
  44.     BytesPerScanline,        /* bytes per scanline in output raster */
  45.     ColorMapSize,        /* number of colors */
  46.     Background,            /* background color */
  47.     CodeSize,            /* Code size, read from GIF header */
  48.     InitCodeSize,        /* Starting code size, used during Clear */
  49.     Code,            /* Value returned by ReadCode */
  50.     MaxCode,            /* limiting value for current code size */
  51.     ClearCode,            /* GIF clear code */
  52.     EOFCode,            /* GIF end-of-information code */
  53.     CurCode, OldCode, InCode,    /* Decompressor variables */
  54.     FirstFree,            /* First free code, generated per GIF spec */
  55.     FreeCode,            /* Decompressor, next free slot in hash table */
  56.     FinChar,            /* Decompressor variable */
  57.     BitMask,            /* AND mask for data size */
  58.     ReadMask;            /* Code AND mask for current code size */
  59.  
  60. boolean Interlace, HasColormap;
  61. boolean Verbose = False;
  62.  
  63. byte *Image;            /* The result array */
  64. byte *RawGIF;            /* The heap array to hold it, raw */
  65. byte *Raster;            /* The raster data stream, unblocked */
  66.  
  67.     /* The hash table used by the decompressor */
  68. int Prefix[4096];
  69. int Suffix[4096];
  70.  
  71.     /* An output array used by the decompressor */
  72. int OutCode[1025];
  73.  
  74.     /* The color map, read from the GIF header */
  75. byte Red[256], Green[256], Blue[256];
  76.  
  77. char *id = "GIF87a";
  78.  
  79.  
  80.  
  81. /*****************************/
  82. LoadGIF(fname)
  83.   char *fname;
  84. /*****************************/
  85. {
  86.     int            filesize;
  87.     register byte  ch, ch1;
  88.     register byte *ptr, *ptr1;
  89.     register int   i,j;
  90.     static byte    lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
  91.     byte           lmask;
  92.  
  93.     if (strcmp(fname,"-")==0) { fp = stdin;  fname = "<stdin>"; }
  94.                          else fp = fopen(fname,"r");
  95.  
  96.     if (!fp) FatalError("file not found");
  97.  
  98.     /* find the size of the file */
  99.     fseek(fp, 0L, 2);
  100.     filesize = ftell(fp);
  101.     fseek(fp, 0L, 0);
  102.  
  103.     if (!(ptr = RawGIF = (byte *) malloc(filesize)))
  104.     FatalError("not enough memory to read gif file");
  105.  
  106.     if (!(Raster = (byte *) malloc(filesize)))
  107.     FatalError("not enough memory to read gif file");
  108.  
  109.     if (fread(ptr, filesize, 1, fp) != 1)
  110.     FatalError("GIF data read failed");
  111.  
  112.     if (strncmp(ptr, id, 6))
  113.     FatalError("not a GIF file");
  114.  
  115.     ptr += 6;
  116.  
  117. /* Get variables from the GIF screen descriptor */
  118.  
  119.     ch = NEXTBYTE;
  120.     RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  121.     ch = NEXTBYTE;
  122.     RHeight = ch + 0x100 * NEXTBYTE;
  123.  
  124.     if (Verbose)
  125.     fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
  126.  
  127.     ch = NEXTBYTE;
  128.     HasColormap = ((ch & COLORMAPMASK) ? True : False);
  129.  
  130.     BitsPerPixel = (ch & 7) + 1;
  131.     numcols = ColorMapSize = 1 << BitsPerPixel;
  132.     BitMask = ColorMapSize - 1;
  133.  
  134.     Background = NEXTBYTE;        /* background color... not used. */
  135.  
  136.     if (NEXTBYTE)        /* supposed to be NULL */
  137.     FatalError("corrupt GIF file (bad screen descriptor)");
  138.  
  139.  
  140. /* Read in global colormap. */
  141.  
  142.     if (HasColormap) {
  143.     if (Verbose)
  144.         fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
  145.         fname, Width,Height,BitsPerPixel, ColorMapSize);
  146.     for (i = 0; i < ColorMapSize; i++) {
  147.         Red[i] = NEXTBYTE;
  148.         Green[i] = NEXTBYTE;
  149.         Blue[i] = NEXTBYTE;
  150.         }
  151.  
  152.         /* Allocate the X colors for this picture */
  153.  
  154.         if (nostrip)  {   /* nostrip was set.  try REAL hard to do it */
  155.             j = 0;
  156.             lmask = lmasks[strip];
  157.             for (i=0; i<numcols; i++) {
  158.                 defs[i].red   = (Red[i]  &lmask)<<8;
  159.                 defs[i].green = (Green[i]&lmask)<<8;
  160.                 defs[i].blue  = (Blue[i] &lmask)<<8;
  161.                 defs[i].flags = DoRed | DoGreen | DoBlue;
  162.                 if (!XAllocColor(theDisp,theCmap,&defs[i])) { 
  163.                     j++;  defs[i].pixel = 0xffff;
  164.                     }
  165.                 cols[i] = defs[i].pixel;
  166.                 }
  167.  
  168.             if (j) {        /* failed to pull it off */
  169.                 XColor ctab[256];
  170.  
  171.                 fprintf(stderr,"failed to allocate %d out of %d colors.  Trying extra hard.\n",j,numcols);
  172.                 
  173.                 /* read in the color table */
  174.                 for (i=0; i<numcols; i++) ctab[i].pixel = i;
  175.                 XQueryColors(theDisp,theCmap,ctab,numcols);
  176.                 
  177.                 for (i=0; i<numcols; i++)
  178.                     if (cols[i] == 0xffff) {        /* an unallocated pixel */
  179.                         int d, mdist, close;
  180.                         unsigned long r,g,b;
  181.  
  182.                         mdist = 100000;   close = -1;
  183.                         r =  Red[i];
  184.                         g =  Green[i];
  185.                         b =  Blue[i];
  186.                         for (j=0; j<numcols; j++) {
  187.                             d = abs(r - (ctab[j].red>>8)) +
  188.                                 abs(g - (ctab[j].green>>8)) +
  189.                                 abs(b - (ctab[j].blue>>8));
  190.                             if (d<mdist) { mdist=d; close=j; }
  191.                             }
  192.                         if (close<0) FatalError("simply can't do it.  Sorry.");
  193.                         bcopy(&defs[close],&defs[i],sizeof(XColor));
  194.                         cols[i] = ctab[close].pixel;
  195.                         }
  196.                 }
  197.             }
  198.  
  199.         else {          /* strip wasn't set, do the best auto-strip */
  200.             j = 0;
  201.             while (strip<8) {
  202.                 lmask = lmasks[strip];
  203.                 for (i=0; i<numcols; i++) {
  204.                     defs[i].red   = (Red[i]  &lmask)<<8;
  205.                     defs[i].green = (Green[i]&lmask)<<8;
  206.                     defs[i].blue  = (Blue[i] &lmask)<<8;
  207.                     defs[i].flags = DoRed | DoGreen | DoBlue;
  208.                     if (!XAllocColor(theDisp,theCmap,&defs[i])) break;
  209.                     cols[i] = defs[i].pixel;
  210.                     }
  211.                 if (i<numcols) {        /* failed */
  212.                     strip++;  j++;
  213.                     XFreeColors(theDisp,theCmap,cols,i,0L);
  214.                     }
  215.                 else break;
  216.                 }
  217.  
  218.             if (j && strip<8)
  219.                 fprintf(stderr,"%s:  %s stripped %d bits\n",cmd,fname,strip);
  220.  
  221.             if (strip==8) {
  222.                 fprintf(stderr,"UTTERLY failed to allocate the desired colors.  Sorry.\n");
  223.                 for (i=0; i<numcols; i++) cols[i]=i;
  224.                 }
  225.             }
  226.         }
  227.  
  228.     else {  /* no colormap in GIF file */
  229.         fprintf(stderr,"%s:  warning!  no colortable in this file.  Winging it.\n",cmd);
  230.         if (!numcols) numcols=256;
  231.         for (i=0; i<numcols; i++) cols[i] = (unsigned long) i;
  232.         }
  233.  
  234. /* Check for image seperator */
  235.  
  236.     if (NEXTBYTE != IMAGESEP)
  237.     FatalError("corrupt GIF file (no image separator)");
  238.  
  239. /* Now read in values from the image descriptor */
  240.  
  241.     ch = NEXTBYTE;
  242.     LeftOfs = ch + 0x100 * NEXTBYTE;
  243.     ch = NEXTBYTE;
  244.     TopOfs = ch + 0x100 * NEXTBYTE;
  245.     ch = NEXTBYTE;
  246.     Width = ch + 0x100 * NEXTBYTE;
  247.     ch = NEXTBYTE;
  248.     Height = ch + 0x100 * NEXTBYTE;
  249.     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  250.  
  251.     if (Verbose)
  252.     fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
  253.         Width, Height, (Interlace) ? "" : "non-");
  254.  
  255.     else 
  256.         fprintf(stderr, "%s:  %s is %dx%d, %d colors, %sinterlaced\n",
  257.        cmd, fname, Width,Height,ColorMapSize,(Interlace) ? "" : "non-");
  258.     
  259.  
  260. /* Note that I ignore the possible existence of a local color map.
  261.  * I'm told there aren't many files around that use them, and the spec
  262.  * says it's defined for future use.  This could lead to an error
  263.  * reading some files. 
  264.  */
  265.  
  266. /* Start reading the raster data. First we get the intial code size
  267.  * and compute decompressor constant values, based on this code size.
  268.  */
  269.  
  270.     CodeSize = NEXTBYTE;
  271.     ClearCode = (1 << CodeSize);
  272.     EOFCode = ClearCode + 1;
  273.     FreeCode = FirstFree = ClearCode + 2;
  274.  
  275. /* The GIF spec has it that the code size is the code size used to
  276.  * compute the above values is the code size given in the file, but the
  277.  * code size used in compression/decompression is the code size given in
  278.  * the file plus one. (thus the ++).
  279.  */
  280.  
  281.     CodeSize++;
  282.     InitCodeSize = CodeSize;
  283.     MaxCode = (1 << CodeSize);
  284.     ReadMask = MaxCode - 1;
  285.  
  286. /* Read the raster data.  Here we just transpose it from the GIF array
  287.  * to the Raster array, turning it from a series of blocks into one long
  288.  * data stream, which makes life much easier for ReadCode().
  289.  */
  290.  
  291.     ptr1 = Raster;
  292.     do {
  293.     ch = ch1 = NEXTBYTE;
  294.     while (ch--) *ptr1++ = NEXTBYTE;
  295.     if ((Raster - ptr1) > filesize)
  296.         FatalError("corrupt GIF file (unblock)");
  297.     } while(ch1);
  298.  
  299.     free(RawGIF);        /* We're done with the raw data now... */
  300.  
  301.     if (Verbose) {
  302.     fprintf(stderr, "done.\n");
  303.     fprintf(stderr, "Decompressing...");
  304.     }
  305.  
  306.  
  307. /* Allocate the X Image */
  308.     Image = (byte *) malloc(Width*Height);
  309.     if (!Image) FatalError("not enough memory for XImage");
  310.  
  311.     theImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,Image,
  312.                          Width,Height,8,Width);
  313.     if (!theImage) FatalError("unable to create XImage");
  314.  
  315.     BytesPerScanline = Width;
  316.  
  317.  
  318. /* Decompress the file, continuing until you see the GIF EOF code.
  319.  * One obvious enhancement is to add checking for corrupt files here.
  320.  */
  321.  
  322.     Code = ReadCode();
  323.     while (Code != EOFCode) {
  324.  
  325. /* Clear code sets everything back to its initial value, then reads the
  326.  * immediately subsequent code as uncompressed data.
  327.  */
  328.  
  329.     if (Code == ClearCode) {
  330.         CodeSize = InitCodeSize;
  331.         MaxCode = (1 << CodeSize);
  332.         ReadMask = MaxCode - 1;
  333.         FreeCode = FirstFree;
  334.         CurCode = OldCode = Code = ReadCode();
  335.         FinChar = CurCode & BitMask;
  336.         AddToPixel(FinChar);
  337.     }
  338.     else {
  339.  
  340. /* If not a clear code, then must be data: save same as CurCode and InCode */
  341.  
  342.         CurCode = InCode = Code;
  343.  
  344. /* If greater or equal to FreeCode, not in the hash table yet;
  345.  * repeat the last character decoded
  346.  */
  347.  
  348.         if (CurCode >= FreeCode) {
  349.         CurCode = OldCode;
  350.         OutCode[OutCount++] = FinChar;
  351.         }
  352.  
  353. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  354.  * through the hash table to its end; each code in the chain puts its
  355.  * associated output code on the output queue.
  356.  */
  357.  
  358.         while (CurCode > BitMask) {
  359.         if (OutCount > 1024)
  360.             FatalError("corrupt GIF file (OutCount)");
  361.         OutCode[OutCount++] = Suffix[CurCode];
  362.         CurCode = Prefix[CurCode];
  363.         }
  364.  
  365. /* The last code in the chain is treated as raw data. */
  366.  
  367.         FinChar = CurCode & BitMask;
  368.         OutCode[OutCount++] = FinChar;
  369.  
  370. /* Now we put the data out to the Output routine.
  371.  * It's been stacked LIFO, so deal with it that way...
  372.  */
  373.  
  374.         for (i = OutCount - 1; i >= 0; i--)
  375.         AddToPixel(OutCode[i]);
  376.         OutCount = 0;
  377.  
  378. /* Build the hash table on-the-fly. No table is stored in the file. */
  379.  
  380.         Prefix[FreeCode] = OldCode;
  381.         Suffix[FreeCode] = FinChar;
  382.         OldCode = InCode;
  383.  
  384. /* Point to the next slot in the table.  If we exceed the current
  385.  * MaxCode value, increment the code size unless it's already 12.  If it
  386.  * is, do nothing: the next code decompressed better be CLEAR
  387.  */
  388.  
  389.         FreeCode++;
  390.         if (FreeCode >= MaxCode) {
  391.         if (CodeSize < 12) {
  392.             CodeSize++;
  393.             MaxCode *= 2;
  394.             ReadMask = (1 << CodeSize) - 1;
  395.         }
  396.         }
  397.     }
  398.     Code = ReadCode();
  399.     }
  400.  
  401.     free(Raster);
  402.  
  403.     if (Verbose)
  404.     fprintf(stderr, "done.\n");
  405.  
  406.     if (fp != stdin)
  407.     fclose(fp);
  408. }
  409.  
  410.  
  411. /* Fetch the next code from the raster data stream.  The codes can be
  412.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  413.  * maintain our location in the Raster array as a BIT Offset.  We compute
  414.  * the byte Offset into the raster array by dividing this by 8, pick up
  415.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  416.  * bring the desired code to the bottom, then mask it off and return it. 
  417.  */
  418. ReadCode()
  419. {
  420. int RawCode, ByteOffset;
  421.  
  422.     ByteOffset = BitOffset / 8;
  423.     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  424.     if (CodeSize >= 8)
  425.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  426.     RawCode >>= (BitOffset % 8);
  427.     BitOffset += CodeSize;
  428.     return(RawCode & ReadMask);
  429. }
  430.  
  431.  
  432. AddToPixel(Index)
  433. byte Index;
  434. {
  435.     *(Image + YC * BytesPerScanline + XC) = cols[Index & (numcols-1)];
  436.  
  437. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  438.  
  439.     if (++XC == Width) {
  440.  
  441. /* If a non-interlaced picture, just increment YC to the next scan line. 
  442.  * If it's interlaced, deal with the interlace as described in the GIF
  443.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  444.  * past the bottom of it
  445.  */
  446.  
  447.     XC = 0;
  448.     if (!Interlace) YC++;
  449.     else {
  450.         switch (Pass) {
  451.         case 0:
  452.             YC += 8;
  453.             if (YC >= Height) {
  454.             Pass++;
  455.             YC = 4;
  456.             }
  457.         break;
  458.         case 1:
  459.             YC += 8;
  460.             if (YC >= Height) {
  461.             Pass++;
  462.             YC = 2;
  463.             }
  464.         break;
  465.         case 2:
  466.             YC += 4;
  467.             if (YC >= Height) {
  468.             Pass++;
  469.             YC = 1;
  470.             }
  471.         break;
  472.         case 3:
  473.             YC += 2;
  474.         break;
  475.         default:
  476.         break;
  477.         }
  478.     }
  479.     }
  480. }
  481.